/**
 * @file Logger.h
 * @author  haifeng ( haifengxiao@icloud.com)
 * @brief
 * @version 0.1
 * @date 2021-07-06
 *
 * @copyright Copyright (c) 2021
 *
 */

#pragma once

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <memory>

#include "LogEvent.h"
#include "LogLevel.h"
#include "LogAppender.h"
#include "LogFormatter.h"
#include "LogEventWrap.h"
#include "../../../inc/singleton.h"
#include "util.h"
#include "../../Thread/Thread.h"

class Logger;
class LoggerManager;

#define CHEN_LOG_LEVEL(logger, level)                                                           \
    if (logger->getLevel() <= level)                                                            \
        Chen::Log::LogEventWrap(Chen::Log::LogEvent::ptr(new Chen::Log::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, Chen::GetThreadId(),                             \
                Chen::GetFiberId(), time(0), Chen::Thread::GetName()))).getSS()


/**
 * @brief 使用流式方式将日志级别debug的日志写入到logger
 */
#define CHEN_LOG_DEBUG(logger) CHEN_LOG_LEVEL(logger, Chen::Log::LogLevel::DEBUG_)

 /**
  * @brief 使用流式方式将日志级别info的日志写入到logger
  */
#define CHEN_LOG_INFO(logger) CHEN_LOG_LEVEL(logger, Chen::Log::LogLevel::INFO)

  /**
   * @brief 使用流式方式将日志级别warn的日志写入到logger
   */
#define CHEN_LOG_WARN(logger) CHEN_LOG_LEVEL(logger, Chen::Log::LogLevel::WARN)

   /**
    * @brief 使用流式方式将日志级别error的日志写入到logger
    */
#define CHEN_LOG_ERROR(logger) CHEN_LOG_LEVEL(logger, Chen::Log::LogLevel::ERROR)

    /**
     * @brief 使用流式方式将日志级别fatal的日志写入到logger
     */
#define CHEN_LOG_FATAL(logger) CHEN_LOG_LEVEL(logger, Chen::Log::LogLevel::FATAL)



#define CHEN_LOG_FMT_LEVEL(logger, level, fmt, ...)                                               \
    if (logger->getLevel() <= level)                                                              \
        Chen::Log::LogEventWrap(sylar::LogEvent::ptr(new Chen::Log::LogEvent(logger, level,       \
                __FILE__, __LINE__, 0, Chen::GetThreadId(), Chen::GetFiberId(), time(0),          \
                    Chen::Thread::GetName()))).getEvent()->format(fmt, __VA_ARGS__);                       

     /**
      * @brief 使用格式化方式将日志级别debug的日志写入到logger
      */
#define CHEN_LOG_FMT_DEBUG(logger, fmt, ...) CHEN_LOG_FMT_LEVEL(logger, Chen::Log::LogLevel::DEBUG_, fmt, __VA_ARGS__)

      /**
       * @brief 使用格式化方式将日志级别info的日志写入到logger
       */
#define CHEN_LOG_FMT_INFO(logger, fmt, ...) CHEN_LOG_FMT_LEVEL(logger, Chen::Log::LogLevel::INFO, fmt, __VA_ARGS__)

       /**
        * @brief 使用格式化方式将日志级别warn的日志写入到logger
        */
#define CHEN_LOG_FMT_WARN(logger, fmt, ...) CHEN_LOG_FMT_LEVEL(logger, Chen::Log::LogLevel::WARN, fmt, __VA_ARGS__)

        /**
         * @brief 使用格式化方式将日志级别error的日志写入到logger
         */
#define CHEN_LOG_FMT_ERROR(logger, fmt, ...) CHEN_LOG_FMT_LEVEL(logger, Chen::Log::LogLevel::ERROR, fmt, __VA_ARGS__)

         /**
          * @brief 使用格式化方式将日志级别fatal的日志写入到logger
          */
#define CHEN_LOG_FMT_FATAL(logger, fmt, ...) CHEN_LOG_FMT_LEVEL(logger, Chen::Log::LogLevel::FATAL, fmt, __VA_ARGS__)

          /**
           * @brief 获取主日志器
           */
#define CHEN_LOG_ROOT() Chen::Log::LoggerMgr::GetInstance()->getRoot()

           /**
            * @brief 获取name的日志器
            */
#define CHEN_LOG_NAME(name) Chen::Log::LoggerMgr::GetInstance()->getLogger(name)

namespace Chen {
    namespace Log {

        class LogAppender;

        class Logger : public std::enable_shared_from_this<Logger> {
            friend class LoggerManager;
        public:
            typedef std::shared_ptr<Logger> ptr;

            /**
             * @brief Construct a new Logger object
             *
             * @param name name of the logger
             */
            Logger(const std::string& name = "root");

            /**
             * @brief Write log
             *
             * @param level
             * @param event
             */
            void log(LogLevel::Level level, LogEvent::ptr event);

            /**
             * @brief Write DEBUG level log
             *
             * @param event log event
             */
            void debug(LogEvent::ptr event);

            /**
             * @brief Wirte INFO level log
             *
             * @param event log event
             */
            void info(LogEvent::ptr event);

            /**
             * @brief Wirte WARN level log
             *
             * @param event log event
             */
            void warn(LogEvent::ptr event);

            /**
             * @brief Wirte ERROR level log
             *
             * @param event log event
             */
            void error(LogEvent::ptr event);

            /**
             * @brief Wirte FATAL level log
             *
             * @param event log event
             */
            void fatal(LogEvent::ptr event);

            /**
             * @brief add appender
             *
             * @param appender log target
             */
            void addAppender(std::shared_ptr<LogAppender> appender);

            /**
             * @brief delete appender
             *
             * @param appender log target
             */
            void delAppender(std::shared_ptr<LogAppender> appender);

            /**
             * @brief clear all appenders
             *
             */
            void clearAppenders();

            /**
             * @brief Get the Level object
             *
             * @return LogLevel::Level
             */
            LogLevel::Level getLevel() const { return m_level; }

            /**
             * @brief Set the Level object
             *
             * @param val
             */
            void setLevel(LogLevel::Level val) { m_level = val; }

            /**
             * @brief Get the Name object
             *
             * @return const std::string&
             */
            const std::string& getName() const { return m_name; }

            /**
             * @brief Set the Formatter pattern
             *
             * @param val
             */
            void setFormatter(const std::string& val);

            /**
             * @brief Set the Formatter object
             *
             * @param val
             */
            void setFormatter(LogFormatter::ptr val);

            /**
             * @brief Get the Formatter object
             *
             * @return LogFormatter::ptr
             */
            LogFormatter::ptr getFormatter();

            /**
             * @brief transfer the config to YANL string
             *
             * @return std::string
             */
            std::string toYamlString();

        private:

            /// logger name
            std::string m_name;
            /// logger lever
            LogLevel::Level m_level;
            /// list of log targer
            std::list<std::shared_ptr<LogAppender>> m_appenders;
            /// the main logger
            Logger::ptr m_root;
            /// log formatter
            LogFormatter::ptr m_formatter;
        };

    }//namespace Log
}//namespace Chen
